
#ifndef CHANNEL_H
#define CHANNEL_H


#include <sys/types.h>
#include <stdbool.h>

typedef struct channel_t* Channel;

/**
    Type of the channel
*/
typedef enum
{
	UNKNOWN,
	SYNCHRONOUS_SYMMETRIC,
	ASYNCHRONOUS_SYMMETRIC,
	SYNCHRONOUS_ASYMMETRIC,
	ASYNCHRONOUS_ASYMMETRIC,
} ChannelType;

typedef struct alternative_t* Alternative;


// channel functions
/**
    Creates a synchronous communication channel, with a given data size and implemented using
    j additional target variables.
    You may use the function ftok to generate the channel key.
    @param key - the key of the channel
    @param size - the size of the data that will be transmitted on the channel
    @param j - number of the additional target variables that will be used for the implementation
    @return a pointer to the channel descriptor or NULL in case of error (setting errno)
*/
struct channel_t *LCcreate_ss( key_t key, size_t size, int j );

/**
    Creates an asynchronous communication channel, with a given data size, asynchrony
    degree and implemented using j additional target variables.
    You may use the function ftok to generate the channel key.
    @param key - the key of the channel
    @param size - the size of the data that will be transmitted on the channel
    @param k - the asynchrony degree
    @param j - number of the additional target variables that will be used for the implementation
    @return a pointer to the channel descriptor or NULL in case of error (setting errno)
*/
struct channel_t *LCcreate_as( key_t key, size_t size, int k, int j);

/**
    This function is used to acquire the communication channel identified by the proper key
    in the addressing space of the caller process.
    @param key - the key of the channel
    @return a pointer to the channel descriptor or NULL in case of error (and set errno)
*/
struct channel_t *LCattach( key_t key );


/**
    Destroy the channel. Its relative shared memory segment will be removed from memory
    only when the last process detatches it.

    @param the channel to destroy (the descriptor)
*/
void LCdestroy( struct channel_t *ch );

/**
    Removes the channel from the virtual memory of the caller

    @param the channel to detatch (the descriptor)
*/
void LCdetatch( struct channel_t *ch );

/**
    Send the message on the given channel.
    This procedure can be blocking if the channel is full (asynchrony degree reached).
    @param ch - channel on which send
    @param msg - the message to send
*/
void LCsend( struct channel_t *ch, char *msg );

/**
    Receive a message from the given channel.
    It can be blocking if the channel is empty.
    @param ch - channel from which receive
    @return the message
*/

char *LCreceive( struct channel_t *ch );


/**
    Return the size of the data type transmittable with the channe;
    @param ch - the channel
    @return the size of the data type
*/
size_t LCgetChannelTypeSize( struct channel_t *ch );

/**
    Returns whether or not the channel is ready to receive
    @param ch - the channel
    @return \b true  if we can receive from the channel, \b false otherwise
*/
bool LCreadyToReceive( struct channel_t *ch );

/**
    Returns whether or not the channel is ready to send
    @param ch - the channel
    @return \b true  if we can send to the channel, \b false otherwise
*/
bool LCreadyToSend( struct channel_t *ch );

/**
    Prints debug informations about the channel
    @param ch - the channel
*/

void printCH( struct channel_t *ch );


// alternative functions

/**
    Creates an alternative command with N predicates (guards), for asymmetric channels.
    @param key - the key of the alternative command that has to be created
    @param n - the number of predicates  that it must have
    @return a descriptor for the alternative command or NULL in case of error (and sets errno)
*/
struct alternative_t *LCcreate_alt( key_t key, int n );

/**
    Sets a predicates of a given alternative command (overwriting it if necessary).
    @param alt - the alternative command
    @param id - the id of the predicate
    @param ch - the channel that is identified by this guards
    @param priority - the priority
    @param cond - the predicate
*/

void LCsetAlt( struct alternative_t *alt, int id, struct channel_t *ch, int priority, bool cond );


/**
    Execute the alternative command. If a guard is verified and it is choosen for a receive
    it will returns its id and a reference to the relative channel (where we can then execute a receive).
    @param alt - the alternative command
    @param **ch - a pointer to a channel descriptor. At the end of the procedure it will reference the channel
        choosen by the alternative command or NULL in case of a skip.
    @return the id of the choosen guard. -1 if all the predicates are false.
*/
int LCpoll( struct alternative_t *alt, struct channel_t **ch );


#endif

